package com.kkshop.spring.gwt;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;

import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GwtRcpEndPointHandlerAdapter extends RemoteServiceServlet implements HandlerAdapter, ApplicationContextAware {

    private static final long serialVersionUID = -7421136737990135393L;

    private static ThreadLocal<Object> handlerHolder = new ThreadLocal<Object>();
    private ApplicationContext applicationContext;

    public long getLastModified(final HttpServletRequest request, final Object handler) {
        return -1;
    }

    public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
        try {
            handlerHolder.set(handler);
            doPost(request, response);
        } finally {
            handlerHolder.set(null);
        }

        return null;
    }

    protected Object getCurrentHandler() {
        return handlerHolder.get();
    }

    public boolean supports(final Object handler) {
        return handler instanceof RemoteService;
    }

    public String processCall(final String payload) throws SerializationException {
        try {
            final RPCRequest rpcRequest = RPC.decodeRequest(payload, getCurrentHandler().getClass(), this);
            return RPC.invokeAndEncodeResponse(
                    getCurrentHandler(),
                    rpcRequest.getMethod(),
                    rpcRequest.getParameters(),
                    rpcRequest.getSerializationPolicy());
        } catch (final IncompatibleRemoteServiceException ex) {
            getServletContext().log("An IncompatibleRemoteServiceException was thrown while processing this call.", ex);
            return RPC.encodeResponseForFailure(null, ex);
        }
    }

    public ServletContext getServletContext() {
        return ((WebApplicationContext) applicationContext).getServletContext();
    }

    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
